﻿namespace SFmpqapi
{
    using System;
    using System.Runtime.InteropServices;

    public class SFmpq
    {
        private const uint MAFA_COMPRESS = 0x200;
        private const uint MAFA_COMPRESS_DEFLATE = 2;
        private const uint MAFA_COMPRESS_STANDARD = 8;
        private const uint MAFA_COMPRESS_WAVE = 0x81;
        private const uint MAFA_COMPRESS_WAVE2 = 0x41;
        private const uint MAFA_COMPRESS_WAVECOMP1 = 0x80;
        private const uint MAFA_COMPRESS_WAVECOMP2 = 0x40;
        private const uint MAFA_COMPRESS_WAVECOMP3 = 1;
        private const uint MAFA_COMPRESS2 = 0x100;
        private const uint MAFA_ENCRYPT = 0x10000;
        private const uint MAFA_EXISTS = 0x80000000;
        private const uint MAFA_MODCRYPTKEY = 0x20000;
        private const uint MAFA_REPLACE_EXISTING = 1;
        private const uint MAFA_UNKNOWN40000000 = 0x40000000;
        private const uint MAWA_QUALITY_HIGH = 1;
        private const uint MAWA_QUALITY_LOW = 2;
        private const uint MAWA_QUALITY_MEDIUM = 0;
        private const uint MOAU_CREATE_ALWAYS = 8;
        private const uint MOAU_CREATE_NEW = 0;
        private const uint MOAU_MAINTAIN_LISTFILE = 1;
        private const uint MOAU_OPEN_ALWAYS = 0x20;
        private const uint MOAU_OPEN_EXISTING = 4;
        private const uint MOAU_READ_ONLY = 0x10;
        private const uint MPQ_ERROR_ALREADY_EXISTS = 0x8520006a;
        private const uint MPQ_ERROR_BAD_OPEN_MODE = 0x8520006c;
        private const uint MPQ_ERROR_COMPACT_ERROR = 0x85300001;
        private const uint MPQ_ERROR_DISK_FULL = 0x85200068;
        private const uint MPQ_ERROR_FILE_NOT_FOUND = 0x85200066;
        private const uint MPQ_ERROR_HASH_TABLE_FULL = 0x85200069;
        private const uint MPQ_ERROR_MPQ_INVALID = 0x85200065;
        private const uint SFILE_INFO_BLOCK_SIZE = 1;
        private const uint SFILE_INFO_COMPRESSED_SIZE = 6;
        private const uint SFILE_INFO_FLAGS = 7;
        private const uint SFILE_INFO_HASH_INDEX = 12;
        private const uint SFILE_INFO_HASH_TABLE_SIZE = 2;
        private const uint SFILE_INFO_LOCALEID = 10;
        private const uint SFILE_INFO_NUM_FILES = 3;
        private const uint SFILE_INFO_PARENT = 8;
        private const uint SFILE_INFO_POSITION = 9;
        private const uint SFILE_INFO_PRIORITY = 11;
        private const uint SFILE_INFO_SIZE = 5;
        private const uint SFILE_INFO_TYPE = 4;
        private const uint SFILE_LIST_MEMORY_LIST = 1;
        private const uint SFILE_LIST_ONLY_KNOWN = 2;
        private const uint SFILE_LIST_ONLY_UNKNOWN = 4;
        private const uint SFILE_OPEN_ALLOW_WRITE = 0x8000;
        private const uint SFILE_OPEN_CD_ROM_FILE = 1;
        private const uint SFILE_OPEN_HARD_DISK_FILE = 0;
        private const uint SFILE_SEARCH_ALL_OPEN = 1;
        private const uint SFILE_SEARCH_CURRENT_ONLY = 0;
        private const uint SFILE_TYPE_FILE = 2;
        private const uint SFILE_TYPE_MPQ = 1;
        private const uint Z_BEST_COMPRESSION = 9;
        private const uint Z_BEST_SPEED = 1;
        private const int Z_DEFAULT_COMPRESSION = -1;
        private const uint Z_NO_COMPRESSION = 0;

        [DllImport("SFmpq.dll")]
        public static extern int MpqAddFileFromBuffer(int hMPQ, byte[] lpBuffer, uint dwLength, string lpFileName, uint dwFlags);
        [DllImport("SFmpq.dll")]
        public static extern int MpqAddFileFromBufferEx(int hMPQ, byte[] lpBuffer, uint dwLength, string lpFileName, uint dwFlags, uint dwCompressionType, uint dwCompressLevel);
        [DllImport("SFmpq.dll")]
        public static extern int MpqAddFileToArchive(int hMPQ, string lpSourceFileName, string lpDestFileName, uint dwFlags);
        [DllImport("SFmpq.dll")]
        public static extern int MpqAddFileToArchiveEx(int hMPQ, string lpSourceFileName, string lpDestFileName, uint dwFlags, uint dwCompressionType, uint dwCompressLevel);
        [DllImport("SFmpq.dll")]
        public static extern int MpqAddWaveFromBuffer(int hMPQ, byte[] lpBuffer, uint dwLength, string lpFileName, uint dwFlags, uint dwQuality);
        [DllImport("SFmpq.dll")]
        public static extern int MpqAddWaveToArchive(int hMPQ, string lpSourceFileName, string lpDestFileName, uint dwFlags, uint dwQuality);
        [DllImport("SFmpq.dll")]
        public static extern uint MpqCloseUpdatedArchive(int hMPQ, uint dwUnknown2);
        [DllImport("SFmpq.dll")]
        public static extern int MpqCompactArchive(int hMPQ);
        [DllImport("SFmpq.dll")]
        public static extern int MpqDeleteFile(int hMPQ, string lpFileName);
        [DllImport("SFmpq.dll")]
        public static extern float MpqGetVersion();
        [DllImport("SFmpq.dll")]
        public static extern string MpqGetVersionString();
        [DllImport("SFmpq.dll")]
        public static extern int MpqOpenArchiveForUpdate(string lpFileName, uint dwFlags, uint dwMaximumFilesInArchive);
        [DllImport("SFmpq.dll")]
        public static extern int MpqRenameFile(int hMPQ, string lpcOldFileName, string lpcNewFileName);
        [DllImport("SFmpq.dll")]
        public static extern int MpqSetFileLocale(int hMPQ, string lpFileName, LCID nOldLocale, LCID nNewLocale);
        [DllImport("SFmpq.dll")]
        public static extern int SFileCloseArchive(int hMPQ);
        [DllImport("SFmpq.dll")]
        public static extern int SFileCloseFile(int hFile);
        [DllImport("SFmpq.dll")]
        public static extern int SFileFindMpqHeader(int hFile);
        [DllImport("SFmpq.dll")]
        public static extern int SFileGetArchiveName(int hMPQ, string lpBuffer, uint dwBufferLength);
        [DllImport("SFmpq.dll")]
        public static extern int SFileGetBasePath(string lpBuffer, uint dwBufferLength);
        [DllImport("SFmpq.dll")]
        public static extern int SFileGetFileArchive(int hFile, ref int hMPQ);
        [DllImport("SFmpq.dll")]
        public static extern int SFileGetFileInfo(int hFile, uint dwInfoType);
        [DllImport("SFmpq.dll")]
        public static extern int SFileGetFileName(int hFile, string lpBuffer, uint dwBufferLength);
        [DllImport("SFmpq.dll")]
        public static extern int SFileGetFileSize(int hFile, ref int lpFileSizeHigh);
        [DllImport("SFmpq.dll")]
        public static extern int SFileListFiles(int hMPQ, string lpFileLists, ref FILELISTENTRY lpListBuffer, uint dwFlags);
        [DllImport("SFmpq.dll")]
        public static extern int SFileOpenArchive(string lpFileName, uint dwPriority, uint dwFlags, ref int hMPQ);
        [DllImport("SFmpq.dll")]
        public static extern int SFileOpenFile(string lpFileName, ref int hFile);
        [DllImport("SFmpq.dll")]
        public static extern int SFileOpenFileEx(int hMPQ, string lpFileName, uint dwSearchScope, ref int hFile);
        [DllImport("SFmpq.dll")]
        public static extern int SFileReadFile(int hFile, byte[] lpBuffer, uint nNumberOfBytesToRead, ref int lpNumberOfBytesRead, IntPtr lpOverlapped);
        [DllImport("SFmpq.dll")]
        public static extern int SFileSetArchivePriority(int hMPQ, uint dwPriority);
        [DllImport("SFmpq.dll")]
        public static extern int SFileSetBasePath(string lpNewBasePath);
        [DllImport("SFmpq.dll")]
        public static extern int SFileSetFilePointer(int hFile, int lDistanceToMove, ref int lplDistanceToMoveHigh, uint dwMoveMethod);
        [DllImport("SFmpq.dll")]
        public static extern LCID SFileSetLocale(LCID nNewLocale);
        [DllImport("SFmpq.dll")]
        public static extern SFMPQVERSION SFMpqGetVersion();
        [DllImport("SFmpq.dll")]
        public static extern string SFMpqGetVersionString();
        [DllImport("SFmpq.dll")]
        public static extern uint SFMpqGetVersionString2(IntPtr lpBuffer, uint dwBufferLength);

        [StructLayout(LayoutKind.Sequential)]
        public struct BLOCKTABLEENTRY
        {
            public uint dwFileOffset;
            public uint dwCompressedSize;
            public uint dwFullSize;
            public uint dwFlags;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct FILELISTENTRY
        {
            public uint dwFileExists;
            [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0, SizeConst=4)]
            public char[] lcLocale;
            public uint dwCompressedSize;
            public uint dwFullSize;
            public uint dwFlags;
            [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0, SizeConst=260)]
            public char[] szFileName;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct HASHTABLEENTRY
        {
            public uint dwNameHashA;
            public uint dwNameHashB;
            [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0, SizeConst=4)]
            public char[] lcLocale;
            public uint dwBlockTableIndex;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct LCID
        {
            [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0, SizeConst=4)]
            public char[] lcLocale;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct MPQARCHIVE
        {
            public IntPtr lpNextArc;
            public IntPtr lpPrevArc;
            [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0, SizeConst=260)]
            private char[] szFileName;
            public uint hFile;
            public uint dwFlags1;
            public uint dwPriority;
            public IntPtr lpLastReadFile;
            public uint dwUnk;
            public uint dwBlockSize;
            public IntPtr lpLastReadBlock;
            public uint dwBufferSize;
            public uint dwMPQStart;
            public IntPtr lpMPQHeader;
            public IntPtr lpBlockTable;
            public IntPtr lpHashTable;
            public uint dwFileSize;
            public uint dwOpenFiles;
            public SFmpq.MPQHEADER MpqHeader;
            public uint dwFlags;
            public string lpFileName;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct MPQFILE
        {
            public IntPtr lpNextFile;
            public IntPtr lpPrevFile;
            [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0, SizeConst=260)]
            private char[] szFileName;
            public uint hPlaceHolder;
            public IntPtr lpParentArc;
            public IntPtr lpBlockEntry;
            public uint dwCryptKey;
            public uint dwFilePointer;
            public uint dwUnk1;
            public uint dwBlockCount;
            public IntPtr lpdwBlockOffsets;
            public uint dwReadStarted;
            public uint dwUnk2;
            public IntPtr lpLastReadBlock;
            public uint dwBytesRead;
            public uint dwBufferSize;
            public uint dwConstant;
            public IntPtr lpHashEntry;
            public string lpFileName;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct MPQHEADER
        {
            public uint dwMPQID;
            public uint dwHeaderSize;
            public uint dwMPQSize;
            public ushort wUnused0C;
            public ushort wBlockSize;
            public uint dwHashTableOffset;
            public uint dwBlockTableOffset;
            public uint dwHashTableSize;
            public uint dwBlockTableSize;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SFMPQVERSION
        {
            public ushort Major;
            public ushort Minor;
            public ushort Revision;
            public ushort Subrevision;
        }
    }
}

